﻿/// <reference path="framework.js" />
/// <reference path="framework-UI.js" />
RexToy.registerType('RexToy.UI.Controls.Block', RexToy.UI.Controls.Container);
RexToy.UI.Controls.Block.extend({
    $constructor: function (text) {
        this.__palette = 'c';
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            $name: 'container',
            className: 'ui-body ui-body-c'
        });
    },

    appendText: function (val, tag) {
        tag = tag || 'div';
        var dom = RexToy.UI.Controls.DomNode.create({
            tag: tag,
            innerHTML: val
        });

        this.__domNode.appendChild(dom);
    },

    setPalette: function (val) {
        var template = 'ui-body-{0}';        
        this.__domNode.replaceClass(String.format(template, this.__palette), String.format(template, val));
        this.__palette = val;
    }
});

RexToy.registerType('RexToy.UI.Controls.VGroupBox', RexToy.UI.Controls.Container);
RexToy.UI.Controls.VGroupBox.extend({
    $constructor: function () {
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            $name: 'container',
            className: 'ui-corner-all ui-controlgroup ui-controlgroup-vertical'
        });
    },

    appendControl: function (ctrl) {
        ctrl.setStandalone(false);
        if (this.__controls.length == 0) {
            ctrl.setFirst(true);
        }

        var lastCtrl = this.__controls.last();
        if (lastCtrl != null) {
            lastCtrl.setLast(false);
        }

        this.$super(ctrl);
        ctrl.setLast(true);
    }
});

RexToy.registerType('RexToy.UI.Controls.CollapseBlock', RexToy.UI.Controls.Container);
RexToy.UI.Controls.CollapseBlock.extend({
    properties: {
        text: String.Empty,
        collapse: false
    },

    events: ['onclick'],

    $constructor: function (head) {
        this.__palette = 'c';
        this.__text = head;
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            className: 'ui-collapsible-contain',
            items: [
                {
                    tag: 'h3',
                    className: 'ui-collapsible-heading',
                    items: [{
                        tag: 'a',
                        $name: 'btn',
                        className: 'ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-shadow ui-corner-all ui-btn-up-c',
                        items: [{
                            tag: 'span',
                            className: 'ui-btn-inner ui-corner-all',
                            items: [
                                {
                                    tag: 'span',
                                    className: 'ui-btn-text',
                                    $name: 'text',
                                    innerHTML: head
                                },
                                {
                                    tag: 'span',
                                    className: 'ui-btn ui-btn-icon-left ui-btn-corner-all ui-shadow ui-btn-up-d',
                                    items: [{
                                        tag: 'span',
                                        className: 'ui-btn-inner ui-btn-corner-all ui-corner-all',
                                        items: [{
                                            tag: 'span',
                                            $name: 'icon',
                                            className: 'ui-icon ui-icon-shadow ui-icon-minus'
                                        }]
                                    }]
                                }
                            ]
                        }]
                    }]
                },
                {
                    tag: 'div',
                    $name: 'container',
                    className: 'ui-collapsible-content'
                }
            ]
        });

        var dom = this.__domNode.$('btn');
        dom.attachEvent('onmouseout', this.mouseup.bind(this))
            .attachEvent('onmousedown', this.mousedown.bind(this))
            .attachEvent('onmouseover', this.mouseover.bind(this))
            .attachEvent('onmouseup', this.mouseup.bind(this));

        dom.attachEvent('ondblclick', this._onclick.bind(this))
            .attachEvent('onclick', this._onclick.bind(this));

        this.setCollapse(this.__collapse);
    },

    setText: function (val) {
        this.__text = val;
        var dom = this.__domNode.$('text');
        dom._element.innerHTML = val;
    },

    setButtonClass: function (status) {
        var dom = this.__domNode.$('btn');
        RexToy.UI.Controls.ButtonStyleUtil.setButtonClass(dom, status, this.__palette);
    },

    setPalette: function (palette) {
        this.setButtonClass('none');
        this.__palette = palette;
        this.setButtonClass('up');
    },

    mouseout: function () {
        this.setButtonClass('up');
    },

    mouseup: function () {
        this.setButtonClass('up');
    },

    mousedown: function () {
        this.setButtonClass('down');
    },

    mouseover: function () {
        this.setButtonClass('hover');
    },

    _onclick: function () {
        this.setCollapse(!this.__collapse);
        this.__fireEvent('onclick');
    },

    setCollapse: function (collapse) {
        this.__collapse = collapse;
        var container = this.__domNode.$('container');
        var icon = this.__domNode.$('icon');
        if (this.__collapse === false) {
            container.appendClass('ui-collapsible-content-collapsed');
            icon.replaceClass('ui-icon-minus', 'ui-icon-plus');
        }
        if (this.__collapse === true) {
            container.removeClass('ui-collapsible-content-collapsed');
            icon.replaceClass('ui-icon-plus', 'ui-icon-minus');
        }
    },

    setStandalone: function (standalone) {
        var dom = this.__domNode.$('btn');
        if (standalone === true) {
            dom.appendClass('ui-btn-corner-all');
            dom.appendClass('ui-shadow');
        }
        if (standalone === false) {
            dom.removeClass('ui-btn-corner-all');
            dom.removeClass('ui-shadow');
        }
    }
});

RexToy.registerType('RexToy.UI.Controls.CollapseBlockGroup', RexToy.UI.Controls.Container);
RexToy.UI.Controls.CollapseBlockGroup.extend({
    $constructor: function () {
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            $name: 'container',
            className: 'ui-collapsible-set'
        });
    },

    appendControl: function (block) {
        if (block instanceof RexToy.UI.Controls.CollapseBlock) {
            block.attachEvent('onclick', this.collapseChange.bind(this));
            this.$super(block);
        } else {
            throw new RexToy.ArgumentException('can only append collapse block control.');
        }
    },

    collapseChange: function (sender) {
        if (sender.getCollapse()) {
            for (var i = 0; i < this.__controls.length; i++) {
                var cb = this.__controls[i];
                if (sender == cb)
                    continue;
                else
                    cb.setCollapse(false);
            }
        }
    }
});

RexToy.registerType("RexToy.UI.Controls.InPlacePopup", RexToy.UI.Controls.Container);
RexToy.UI.Controls.InPlacePopup.extend({
    properties: {
        dragEventBubble: false
    },

    $constructor: function () {
        this.__palette = 'a';
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            $name: 'container',
            className: 'ui-inplace-popup ui-overlay-shadow ui-corner-all ui-inplace-popup-hidden ui-body-a'
        });

        this.__backNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            className: 'ui-selectmenu-screen ui-screen-hidden'
        });
        this.__backNode.attachEvent('onclick', this._clickOutside.bind(this));
    },

    _clickOutside: function () {
        this.close();
    },

    show: function (position) {
        if (!position)
            position = new RexToy.UI.Point(0, 0);

        var x = position.getX();
        var w = this.getSize().getWidth();
        if (x + w > RexToy.UI.Window.getSize().getWidth()) {
            x = RexToy.UI.Window.getSize().getWidth() - w;
        }
        var y = position.getY();
        var h = this.getSize().getHeight();
        if (y + h > RexToy.UI.Window.getSize().getHeight()) {
            y = RexToy.UI.Window.getSize().getHeight() - h;
        }

        this.__domNode.removeClass('ui-inplace-popup-hidden');
        var style = this.__domNode.getStyle();
        style.left = x + 'px';
        style.top = y + 'px';

        RexToy.UI.Window.getDocumentBody().appendChild(this.__backNode);
        this.__backNode.removeClass('ui-screen-hidden');
    },

    close: function () {
        var style = this.__domNode.getStyle();
        style.left = null;
        style.top = null;
        this.__domNode.appendClass('ui-inplace-popup-hidden');

        RexToy.UI.Window.getDocumentBody().removeChild(this.__backNode);
        this.__backNode.appendClass('ui-screen-hidden');
    },

    destroy: function () {
        this.$super();
        RexToy.UI.Window.getDocumentBody().removeChild(this.__backNode);
    },

    setPalette: function (val) {
        var template = 'ui-body-{0}';
        this.__domNode.replaceClass(String.format(template, this.__palette), String.format(template, val));
        this.__palette = val;
    }
});

//Note:The layout is always 'VPanel' if no panel defined, so there will be no 'VPanel' class.
RexToy.registerType("RexToy.UI.Controls.HPanel", RexToy.UI.Controls.Container);
RexToy.UI.Controls.HPanel.extend({
    properties: {
        columns: 0,
        sizeUpdate: true
    },

    setColumns: function (val) {
        throw new RexToy.ReadOnlyPropertyException('columns');
    },

    $constructor: function (columns) {//Note:only 2,3,4,5 is valid
        var arr = ['a', 'b', 'c', 'd', 'e'];
        if (columns < 2 || columns > 5)
            throw new RexToy.ArgumentOutOfRangeException('valid value is 2 <= cols <= 5');
        this.__columns = columns;
        var hostClass = String.format('ui-grid-{0}', arr[columns - 2]);
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            $name: 'host',
            className: hostClass
        });

        for (var i = 0; i < columns; i++) {
            var childClass = String.format('ui-block-{0}', arr[i]);
            var child = RexToy.UI.Controls.DomNode.create({
                tag: 'div',
                className: childClass
            });
            this.__domNode.appendChild(child);
        }

        this._colctrls = [];
        for (var i = 0; i < columns; i++) {
            this._colctrls.push([]);
        }
    },

    setColumnsRatio: function (ratio) {
        var sum = 0;
        for (var i = 0; i < ratio.length; i++) {
            sum += ratio[i];
        }
        var perc = [];
        for (var i = 0; i < ratio.length; i++) {
            var p = ratio[i] / sum * 100;
            var str = p.toFixed(2) + '%';
            perc.push(str);
        }
        this.setColumnsPercent(perc);
    },

    setColumnsPercent: function (perc) {
        for (var i = 0; i < perc.length; i++) {
            var style = this.__domNode.children[i].getStyle();
            style.width = perc[i];
        }
    },

    appendControl: function (col, ctrl) {
        ctrl.init();
        if (col < 0 || col >= this.__columns)
            throw new RexToy.ArgumentOutOfRangeException('col not valid');
        this.__domNode.children[col].appendChild(ctrl.getDomNode());
        this._colctrls[col].push(ctrl);
    },

    removeControl: function (col, ctrl) {
        if (col < 0 || col >= this.__columns)
            throw new RexToy.ArgumentOutOfRangeException('col not valid');
        this.__domNode.children[col].removeChild(ctrl.getDomNode());
        this._colctrls[col].remove(ctrl);
    },

    clearControls: function () {
        for (var i = 0; i < this.__domNode.children.length; i++) {
            var dom = this.__domNode.children[i];
            for (var j = 0; j < this._colctrls[i].length; j++) {
                dom.removeChild(this._colctrls[i][j].getDomNode());
            }
            this._colctrls[i] = [];
        }
    },

    insertControlAt: function (col, ctrl, idx) {
        if (col < 0 || col >= this.__columns)
            throw new RexToy.ArgumentOutOfRangeException('col not valid');

        var dom = this.__domNode.children[col].insertChildAt(ctrl.getDomNode(), idx);
        this._colctrls[col].insertAt(ctrl, idx);
    },

    render: function (sz) {
        for (var i = 0; i < this.__columns; i++) {
            var container = this.__domNode.children[i];
            container.setHeight(sz.getHeight());            
            var size = new RexToy.UI.Size(container.getWidth(), container.getHeight());
            var h = sz.getHeight();
            var resizeCtrl = null;
            for (var j = 0; j < this._colctrls[i].length; j++) {
                var ctrl = this._colctrls[i][j];
                if (ctrl.getIsContainer() && ctrl.getSizeUpdate()) {
                    if (resizeCtrl != null)
                        throw new RexToy.UI.LayoutException('container can have only 1 resizable control!');
                    else
                        resizeCtrl = ctrl;
                } else {
                    h -= ctrl.getSize().getHeight();
                    if (ctrl.getIsContainer())
                        ctrl.render(ctrl.getSize());
                }
            }

            if (resizeCtrl) {
                resizeCtrl.getDomNode().setHeight(h);
                resizeCtrl.render(new RexToy.UI.Size(container.getWidth(), h));
            }
        }
    }
});

RexToy.registerType("RexToy.UI.Controls.GridPanel", RexToy.UI.Controls.Container);
RexToy.UI.Controls.GridPanel.extend({
    properties: {
        columns: 0,
        rows: 0,
        sizeUpdate: true
    },

    setColumns: function (val) {
        throw new RexToy.ReadOnlyPropertyException('columns');
    },

    setRows: function (val) {
        throw new RexToy.ReadOnlyPropertyException('rows');
    },

    $constructor: function (rows, columns) {
        var arr = ['a', 'b', 'c', 'd', 'e'];
        if (columns < 2 || columns > 5)
            throw new RexToy.ArgumentOutOfRangeException('valid value is 2 <= cols <= 5');
        this.__columns = columns;
        this.__rows = rows;
        var hostClass = String.format('ui-grid-{0}', arr[columns - 2]);
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            $name: 'host',
            className: hostClass
        });

        for (var r = 0; r < rows; r++) {
            for (var i = 0; i < columns; i++) {
                var childClass = String.format('ui-block-{0}', arr[i]);
                var child = RexToy.UI.Controls.DomNode.create({
                    tag: 'div',
                    className: childClass
                });
                this.__domNode.appendChild(child);
            }
        }

        this._cellctrls = [];
        for (var i = 0; i < this.__rows; i++) {
            for (var j = 0; j < this.__columns; j++) {
                this._cellctrls.push([]);
            }
        }
    },

    appendControl: function (row, col, ctrl) {
        if (col < 0 || col >= this.__columns)
            throw new RexToy.ArgumentOutOfRangeException('col not valid');
        if (row < 0 || row >= this.__rows)
            throw new RexToy.ArgumentOutOfRangeException('row not valid');

        ctrl.init();
        this.__domNode.children[row * this.__columns + col].appendChild(ctrl.getDomNode());
        this._cellctrls[row * this.__columns + col].push(ctrl);
    },

    removeControl: function (row, col, ctrl) {
        if (col < 0 || col >= this.__columns)
            throw new RexToy.ArgumentOutOfRangeException('col not valid');
        if (row < 0 || row >= this.__rows)
            throw new RexToy.ArgumentOutOfRangeException('row not valid');

        this.__domNode.children[row * this.__columns + col].removeChild(ctrl.getDomNode());
        this._cellctrls[row * this.__columns + col].remove(ctrl);
    },

    insertControlAt: function (row, col, ctrl, idx) {
        if (col < 0 || col >= this.__columns)
            throw new RexToy.ArgumentOutOfRangeException('col not valid');
        if (row < 0 || row >= this.__rows)
            throw new RexToy.ArgumentOutOfRangeException('row not valid');

        this.__domNode.children[row * this.__columns + col].insertChildAt(ctrl.getDomNode(), idx);
        this._cellctrls[row * this.__columns + col].insertAt(ctrl, idx);
    },

    clearControls: function () {
        for (var i = 0; i < this.__rows; i++) {
            for (var j = 0; j < this.__columns; j++) {
                var dom = this.__domNode.children[i * this.__columns + j];
                var arr = this._cellctrls[i * this.__columns + j];
                for (var k = 0; k < arr.length; k++) {
                    dom.removeChild(arr[k].getDomNode());
                }
                this._cellctrls[i * this.__columns + j] = [];
            }
        }
    },

    render: function (size) {
        var rowHeight = size.getHeight() / this.__rows;

        for (var i = 0; i < this.__rows; i++) {
            for (var j = 0; j < this.__columns; j++) {
                var container = this.__domNode.children[i * this.__columns + j];
                container.setHeight(rowHeight);

                var h = rowHeight;
                var resizeCtrl = null;
                for (var k = 0; k < this._cellctrls[i * this.__columns + j].length; k++) {
                    var ctrl = this._cellctrls[i * this.__columns + j][k];
                    if (ctrl.getIsContainer() && ctrl.getSizeUpdate()) {
                        if (resizeCtrl != null)
                            throw new RexToy.UI.LayoutException('container can have only 1 resizable control!');
                        else
                            resizeCtrl = ctrl;
                    } else {
                        h -= ctrl.getSize().getHeight();
                        if (ctrl.getIsContainer())
                            ctrl.render(ctrl.getSize());
                    }
                }
                if (resizeCtrl) {
                    resizeCtrl.getDomNode().setHeight(h);
                    resizeCtrl.render(new RexToy.UI.Size(container.getWidth(), h));
                }
            }
        }
    }
});

RexToy.registerType('RexToy.UI.Controls.Table', RexToy.UI.Controls.Control);
RexToy.UI.Controls.Table.extend({
    properties: {
        dragEventBubble: false,
        rows: []
    },

    $constructor: function () {
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'table',
            cellPadding: '0',
            cellSpacing: '0',
            className: 'ui-table',
            border: '0'
        });
    },

    getRow: function (idx) {
        return this.__rows[idx];
    },

    getRowCount: function () {
        return this.__domNode._element.rows.length;
    },

    insertRow: function (idx) {
        var rowDom = this.__domNode._element.insertRow(idx);
        var row = new RexToy.UI.Controls.TableRow(rowDom);
        this.__rows.insertAt(row, idx);
        return row;
    },

    deleteRow: function (idx) {
        this.__domNode._element.deleteRow(idx);
        this.__rows.removeAt(idx);
    },

    getCell: function (row, col) {
        return this.getRow(row).getCell(col);
    }
});

RexToy.UI.Controls.Table.create = function (row, col) {
    var t = new RexToy.UI.Controls.Table();
    for (var i = 0; i < row; i++) {
        var r = t.insertRow(0);
        for (var j = 0; j < col; j++) {
            r.insertCell(0);
        }
    }
    return t;
};

RexToy.registerType('RexToy.UI.Controls.TableRow', RexToy.UI.Controls.Control);
RexToy.UI.Controls.TableRow.extend({
    properties: {
        dragEventBubble: false,
        cells: []
    },

    $constructor: function (domRow) {
        this.__domNode = new RexToy.UI.Controls.DomNode(domRow);
    },

    getCell: function (idx) {
        return this.__cells[idx];
    },

    getCellCount: function () {
        return this.__domNode._element.cells.length;
    },

    insertCell: function (idx) {
        var cellDom = this.__domNode._element.insertCell(idx);
        //cellDom.className = 'ui-td';
        var cell = new RexToy.UI.Controls.TableCell(cellDom);
        this.__cells.insertAt(cell, idx);
        return cell;
    },

    deleteCell: function (idx) {
        this.__domNode._element.deleteCell(idx);
        this.__cells.removeAt(idx);
    }
});

RexToy.registerType('RexToy.UI.Controls.TableCell', RexToy.UI.Controls.Container);
RexToy.UI.Controls.TableCell.extend({
    properties: {
        dragEventBubble: false
    },

    $constructor: function (domCell) {
        this.__domNode = new RexToy.UI.Controls.DomNode(domCell);
    },

    appendControl: function (ctrl) {
        ctrl.init();
        this.__domNode.appendChild(ctrl.getDomNode());
        this.__controls.push(ctrl);
    },

    removeControl: function (ctrl) {
        this.__domNode.removeChild(ctrl.getDomNode());
        this.__controls.remove(ctrl);
    },

    getColSpan: function () {
        return this.__domNode._element.colSpan;
    },

    setColSpan: function (span) {
        this.__domNode._element.colSpan = span;
    },

    getRowSpan: function () {
        return this.__domNode._element.rowSpan;
    },

    setRowSpan: function (span) {
        return this.__domNode._element.rowSpan = span;
    }
});

RexToy.registerType('RexToy.UI.Controls.ScrollBase', RexToy.UI.Controls.Container);
RexToy.UI.Controls.ScrollBase.extend({
    properties: {
        dragEnable: true,
        dragEventBubble: false,
        allowVertical: true,
        allowHorizon: false,
        sizeUpdate: true
    },

    _posX: 0,
    _posY: 0,
    _mTop: 0,
    _mLeft: 0,

    $constructor: function () {
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            className: 'ui-scroll-container ui-body-c',
            items: [
                {
                    tag: 'div',
                    $name: 'container',
                    className: 'ui-scroll'
                }
            ]
        });
    },

    render: function (size) {
        this.$super(size);
    },

    resetScroll: function () {
        var style = this.__domNode.$('container').getStyle();
        if (this.__allowHorizon) {
            this._mLeft = 0;
            style.marginLeft = '0px';
        }
        if (this.__allowVertical) {
            this._mTop = 0;
            style.marginTop = '0px';
        }
    },

    startDrag: function () {
        this._start_msec = new Date().getTime();
        var e = this.__domNode.$('container')._element;
        this.dragHeight = 0;
        this.dragWidth = 0;
        for (var i = 0; i < this.__controls.length; i++) {
            this.dragHeight += this.__controls[i].getSize().getHeight();
        }
        if (this.__controls.length > 0) {
            this.dragWidth = this.__controls[0].getSize().getWidth();
        }

        e = this.__domNode._element;
        this.viewWidth = Math.min(e.scrollWidth, e.offsetWidth, e.clientWidth);
        this.viewHeight = Math.min(e.scrollHeight, e.offsetHeight, e.clientHeight);
    },

    stopDrag: function (delta) {
        this._stop_msec = new Date().getTime();
        var t = this._stop_msec - this._start_msec;

        var style = this.__domNode.$('container').getStyle();
        //Note:Inertia, calc speed, and assume a = 50px/s/s
        var vx = delta.x / t * 1000;
        var vy = delta.y / t * 1000;
        var a = 50;
        var ax = (vx > 0) ? -a : a;
        var ay = (vy > 0) ? -a : a;

        var sid;
        var interval = 25;
        var move_y = this.__allowVertical && (this.dragHeight > this.viewHeight);
        var move_x = this.__allowHorizon && (this.dragWidth > this.viewWidth);

        function _m() {
            //Note:Vertical
            if (move_y) {
                vy += ay;
                if (Math.abs(vy) <= a) {
                    move_y = false;
                    this._posY = this._mTop;
                } else {
                    this._mTop += (vy * interval / 1000)
                    style.marginTop = this._mTop + 'px';

                    if (vy < 0 && this.viewHeight - this._mTop > this.dragHeight) {
                        this._mTop = this._posY = this.viewHeight - this.dragHeight;
                        style.marginTop = this._mTop + 'px';
                        move_y = false;
                    }
                    if (vy > 0 && this._mTop > 0) {
                        this._mTop = this._posY = 0;
                        style.marginTop = this._mTop + 'px';
                        move_y = false;
                    }
                }
            }

            //Note:Horizon
            if (move_x) {
                vx += ax;
                if (Math.abs(vx) <= a) {
                    move_x = false;
                    this._posX = this._mLeft;
                } else {
                    this._mLeft += (vx * interval / 1000)
                    style.marginLeft = this._mLeft + 'px';

                    if (vx < 0 && this.viewWidth - this._mLeft > this.dragWidth) {
                        this._mLeft = this._posX = this.viewWidth - this.dragWidth;
                        style.marginLeft = this._mLeft + 'px';
                        move_x = false;
                    }
                    if (vx > 0 && this._mLeft > 0) {
                        this._mLeft = this._posX = 0;
                        style.marginLeft = this._mLeft + 'px';
                        move_x = false;
                    }
                }
            }

            if (!move_x && !move_y) {
                clearInterval(sid);
            }
        };
        var __m = _m.bind(this);
        sid = setInterval(__m, interval);
    },

    dragging: function (delta) {
        var style = this.__domNode.$('container').getStyle();

        if (this.__allowHorizon) {
            if (this.dragWidth <= this.viewWidth) {
                this._mLeft = 0;
            } else if (delta.x > 0 && this._posX + delta.x > 0) {
                //Note:Do nothing.
            } else if (delta.x < 0 && this._posX + delta.x + this.dragWidth < this.viewWidth) {
                //Note:Do nothing.
            } else {
                this._mLeft = this._posX + delta.x;
            }
            style.marginLeft = this._mLeft + 'px';
        }

        if (this.__allowVertical) {
            if (this.dragHeight <= this.viewHeight) {
                this._mTop = 0;
            } else if (delta.y > 0 && this._posY + delta.y > 0) {
                //Note:Do nothing.
            } else if (delta.y < 0 && this.viewHeight - (this._posY + delta.y) > this.dragHeight) {
                //Note:Do nothing.
            } else {
                this._mTop = this._posY + delta.y;
            }

            style.marginTop = this._mTop + 'px';
        }
    }
});

RexToy.UI.Controls.DialogResult = {
    None: 0,
    OK: 1,
    Cancel: 2,
    Yes: 4,
    No: 8
};

RexToy.registerType('RexToy.UI.Controls.Dialog', RexToy.UI.Controls.Container);
RexToy.UI.Controls.Dialog.extend({
    properties: {
        dragEventBubble: false,
        show: false,
        background: 'a',
        dialogResult: RexToy.UI.Controls.DialogResult.None
    },

    events: ['onclose'],

    $constructor: function (head, transition) {
        this.__palette = 'b';
        this._transition = transition || RexToy.UI.Controls.TransitionMode.SlideDown;
        this.outClass = String.format('{0} out reverse', this._transition);
        this.inClass = String.format('{0} in', this._transition);
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            className: 'ui-dialog ui-page ui-body-a ui-page-active',
            'data-role': 'dialog',
            items: [
                {
                    tag: 'div',
                    $name: 'head',
                    className: 'ui-corner-top ui-overlay-shadow ui-bar-b ui-header',
                    items: [
                        {
                            tag: 'a',
                            $name: 'X',
                            className: 'ui-btn-left ui-btn ui-btn-icon-notext ui-btn-corner-all ui-shadow ui-btn-up-b',
                            title: 'Close',
                            items: [{
                                tag: 'span',
                                className: 'ui-btn-inner ui-btn-corner-all',
                                items: [
                                    {
                                        tag: 'span',
                                        className: 'ui-btn-text'
                                    },
                                    {
                                        tag: 'span',
                                        className: 'ui-icon ui-icon-delete ui-icon-shadow'
                                    }
                                ]
                            }]
                        },
                        {
                            tag: 'h1',
                            className: 'ui-title',
                            innerHTML: head
                        }
                    ]
                },
                {
                    tag: 'div',
                    $name: 'container',
                    className: 'ui-content ui-body-b ui-corner-bottom ui-overlay-shadow'
                }
            ]
        });

        this.__domNode.setHeight(RexToy.UI.Window.getScrollSize().getHeight());
        var x = this.__domNode.$('X');
        x.attachEvent('onmouseover', this._mouseover.bind(this))
         .attachEvent('onmouseout', this._mouseout.bind(this))
         .attachEvent('onclick', this._onclick.bind(this));

        RexToy.UI.Window.attachEvent('onresize', this._resize.bind(this));

        this.__domNode._element.addEventListener('webkitAnimationEnd', this.__webkit_animEnd.bind(this));
    },

    _resize: function () {
        this.__domNode.setHeight(RexToy.UI.Window.getScrollSize().getHeight());
    },

    setPalette: function (val) {
        var template;
        var container = this.__domNode.$('container');
        template = 'ui-body-{0}';
        container.replaceClass(String.format(template, this.__palette), String.format(template, val));

        var btnX = this.__domNode.$('X');
        template = 'ui-btn-up-{0}';
        btnX.replaceClass(String.format(template, this.__palette), String.format(template, val));

        var head = this.__domNode.$('head');
        template = 'ui-bar-{0}';
        head.replaceClass(String.format(template, this.__palette), String.format(template, val));

        this.__palette = val;
    },

    setBackground: function (val) {
        var template = 'ui-body-{0}';
        this.__domNode.replaceClass(String.format(template, this.__background), String.format(template, val));
        this.__background = val;
    },

    _mouseover: function () {
        var x = this.__domNode.$('X');
        var oldname = String.format('ui-btn-up-{0}', this.__palette);
        var newname = String.format('ui-btn-over-{0}', this.__palette);
        x.replaceClass(oldname, newname);
    },

    _mouseout: function () {
        var x = this.__domNode.$('X');
        var newname = String.format('ui-btn-up-{0}', this.__palette);
        var oldname = String.format('ui-btn-over-{0}', this.__palette);
        x.replaceClass(oldname, newname);
    },

    _onclick: function () {
        this.__dialogResult = RexToy.UI.Controls.DialogResult.None;
        this.close();
    },

    show: function () {
        this.__show = true;
        this.__domNode.replaceClass(this.outClass, this.inClass);

        this.__domNode.getStyle().display = 'block';
        this.render();
    },

    __webkit_animEnd: function () {
        if (!this.__show) {
            this.__domNode.getStyle().display = 'none';
            this.destroy();
        }
    },

    close: function () {
        this.__show = false;
        this.__domNode.replaceClass(this.inClass, this.outClass);

        if (!RexToy.UI.Capability.CssTransitions) {
            this.__domNode.getStyle().display = 'none';
            this.destroy();
        }
        this.__fireEvent('onclose');
    }
});

RexToy.UI.Controls.DialogButtons = {
    OK: 1,
    OKCancel: 3,
    YesNo: 12,
    YesNoCancel: 14
};

RexToy.registerType('RexToy.UI.Controls.MessageBox', RexToy.UI.Controls.Dialog);
RexToy.UI.Controls.MessageBox.extend({
    $constructor: function (head, transition, msg, buttons) {
        var content = new RexToy.UI.Controls.Content(msg);
        this.appendControl(content);

        this.init(buttons || RexToy.UI.Controls.DialogButtons.OK);
    },

    init: function (buttons) {
        var pnl = new RexToy.UI.Controls.VGroupBox();
        this.appendControl(pnl);
        //Extend: use HPanel?
        var build;
        if (buttons & RexToy.UI.Controls.DialogResult.OK) {
            var btn = new RexToy.UI.Controls.Button('OK');
            btn.setInline(true);
            btn.value = RexToy.UI.Controls.DialogResult.OK;
            pnl.appendControl(btn);
            btn.attachEvent('onclick', this.onClick.bind(this));
        }
        if (buttons & RexToy.UI.Controls.DialogResult.Yes) {
            var btn = new RexToy.UI.Controls.Button('Yes');
            btn.setInline(true);
            btn.value = RexToy.UI.Controls.DialogResult.Yes;
            pnl.appendControl(btn);
            btn.attachEvent('onclick', this.onClick.bind(this));
        }
        if (buttons & RexToy.UI.Controls.DialogResult.No) {
            var btn = new RexToy.UI.Controls.Button('No');
            btn.setInline(true);
            btn.value = RexToy.UI.Controls.DialogResult.No;
            pnl.appendControl(btn);
            btn.attachEvent('onclick', this.onClick.bind(this));
        }
        if (buttons & RexToy.UI.Controls.DialogResult.Cancel) {
            var btn = new RexToy.UI.Controls.Button('Cancel');
            btn.setInline(true);
            btn.value = RexToy.UI.Controls.DialogResult.Cancel;
            pnl.appendControl(btn);
            btn.attachEvent('onclick', this.onClick.bind(this));
        }
    },

    onClick: function (sender) {
        this.__dialogResult = sender.value;
        this.close();
    }
});

//Extend: Add a page type which do not resize -- which do not have fixed header/footer
RexToy.registerType('RexToy.UI.Controls.Page', RexToy.UI.Controls.Container);
RexToy.UI.Controls.Page.extend({
    properties: {
        dragEventBubble: false
    },

    events: ['onclose'],

    $constructor: function (transition) {
        this._useTrans = !!transition;
        this._transition = transition;

        if (this._useTrans) {
            this.outClass = String.format('{0} out reverse', this._transition);
            this.inClass = String.format('{0} in', this._transition);
        }

        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            className: 'ui-page ui-body-c',
            'data-role': 'page',
            items: [
                {
                    tag: 'div',
                    $name: 'head'
                },
                {
                    tag: 'div',
                    $name: 'container'
                },
                {
                    tag: 'div',
                    $name: 'foot'
                }
            ]
        });

        if (RexToy.UI.Capability.CssTransitions) //Note:fix error in IE8-
            this.__domNode._element.addEventListener('webkitAnimationEnd', this.__webkit_animEnd.bind(this));

        RexToy.UI.Window.attachEvent('onresize', this._resize.bind(this));
    },

    _resize: function () {
        var size = this._calcSize();
        this.render(size);
    },

    setFixedCompensate: function (header, footer) {
        //Refactor:assert type or null
        this._header = header;
        this._footer = footer;
    },

    show: function () {
        this.__show = true;

        if (this._useTrans) {
            this.__domNode.replaceClass(this.outClass, this.inClass);
        }

        this.__domNode.appendClass('ui-page-active');
        this.__domNode.getStyle().display = 'block';
        this.__domNode.getStyle().zIndex = 5;

        var size = this._calcSize();
        this.render(size);
    },

    _calcSize: function () {
        //Note:adjust for header/footer, adjust compensate div.
        var height = RexToy.UI.Window.getSize().getHeight();
        var fStyle = this.__domNode.$('foot').getStyle();
        if (this._footer) {
            var fHeight = this._footer.getSize().getHeight();
            height -= fHeight;
            fStyle.height = fHeight + 'px';
        } else {
            fStyle.height = '0px';
        }
        var hStyle = this.__domNode.$('head').getStyle();
        if (this._header) {
            var hHeight = this._header.getSize().getHeight();
            height -= hHeight;
            hStyle.height = hHeight + 'px';
        } else {
            hStyle.height = '0px';
        }
        this.__domNode.$('container').setHeight(height);
        return RexToy.UI.Window.getSize();
    },

    render: function (size) {
        var dom = this.__domNode.$('container');

        var h = dom.getHeight();
        var resizeCtrl = null;
        var size = new RexToy.UI.Size(dom.getWidth(), dom.getHeight());
        for (var i = 0; i < this.__controls.length; i++) {
            var ctrl = this.__controls[i];
            if (ctrl instanceof RexToy.UI.Controls.FixedHeaderBar || ctrl instanceof RexToy.UI.Controls.FixedFooterBar)
                continue;
            if (ctrl.getIsContainer() && ctrl.getSizeUpdate()) {
                if (resizeCtrl != null) {
                    throw new RexToy.UI.LayoutException('container can have only 1 resizable control!');
                } else {
                    resizeCtrl = ctrl;
                }
            } else {
                if (ctrl.getIsContainer())
                    ctrl.render(ctrl.getSize());
                h -= ctrl.getSize().getHeight();
            }
        }
        if (resizeCtrl) {
            resizeCtrl.getDomNode().setHeight(h);
            resizeCtrl.render(new RexToy.UI.Size(dom.getWidth(), h));
        }
    },

    __webkit_animEnd: function () {
        if (!this.__show) {
            this.__domNode.getStyle().display = 'none';
            this.__domNode.removeClass('ui-page-active');
            this.__domNode.getStyle().zIndex = 0;
        }
    },

    close: function () {
        this.__show = false;

        if (this._useTrans) {
            this.__domNode.replaceClass(this.inClass, this.outClass);
        }

        if (!RexToy.UI.Capability.CssTransitions || !this._useTrans) {
            this.__domNode.getStyle().display = 'none';
            this.__domNode.removeClass('ui-page-active');
            this.__domNode.getStyle().zIndex = 0;
        }

        this.__fireEvent('onclose');
    }
});

RexToy.registerType('RexToy.UI.Controls.HeaderBar', RexToy.UI.Controls.Container);
RexToy.UI.Controls.HeaderBar.extend({
    properties: {
        text: String.Empty,
        dragEventBubble: false
    },

    $constructor: function (text) {
        this.__palette = 'a';
        this.__text = text;
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            className: 'ui-header ui-bar-a',
            $name: 'container',
            items: [{
                tag: 'h1',
                $name: 'content',
                className: 'ui-title',
                innerHTML: text
            }]
        });
    },

    setText: function (val) {
        this.__text = val;
        var dom = this.__domNode.$('content');
        dom._element.innerHTML = this.__text;
    },

    setPalette: function (val) {
        var template = 'ui-bar-{0}';
        this.__domNode.replaceClass(String.format(template, this.__palette), String.format(template, val));
        this.__palette = val;
    }
});

RexToy.registerType('RexToy.UI.Controls.FooterBar', RexToy.UI.Controls.Container);
RexToy.UI.Controls.FooterBar.extend({
    properties: {
        dragEventBubble: false
    },

    $constructor: function () {
        this.__palette = 'a';
        this.__domNode = RexToy.UI.Controls.DomNode.create({
            tag: 'div',
            $name: 'container',
            className: 'ui-bar ui-footer ui-bar-a'
        });
    },

    setPalette: function (val) {
        var template = 'ui-bar-{0}';
        this.__domNode.removeClass(String.format(template, this.__palette), String.format(template, val));
        this.__palette = val;
    }
});

RexToy.registerType('RexToy.UI.Controls.FixedHeaderBar', RexToy.UI.Controls.HeaderBar);
RexToy.UI.Controls.FixedHeaderBar.extend({
    $constructor: function () {
        //Note:style = 'position:fixed; bottom:0; width:100%'        
        var style = this.__domNode.getStyle();
        style.position = 'fixed';
        style.top = 0;
        style.width = '100%';
        style.zIndex = 5;
    }
});

RexToy.registerType('RexToy.UI.Controls.FixedFooterBar', RexToy.UI.Controls.FooterBar);
RexToy.UI.Controls.FixedFooterBar.extend({
    $constructor: function () {
        //Note:style = 'position:fixed; bottom:0; width:100%'
        var style = this.__domNode.getStyle();
        style.position = 'fixed';
        style.bottom = 0;
        style.width = '100%';
        style.zIndex = 5;
    }
});

RexToy.registerType('RexToy.UI.Controls.HeaderBarPosition');
RexToy.UI.Controls.HeaderBarPosition = {
    Left: 'left',
    Right: 'right'
};

RexToy.registerType('RexToy.UI.Controls.ToolBarButton', RexToy.UI.Controls.IconButton);
RexToy.UI.Controls.ToolBarButton.extend({
    properties: {
        position: 'left'
    },

    $constructor: function () {
        var pos = String.format('ui-btn-{0}', this.__position);
        this.__domNode.appendClass(pos);

        var style = this.__domNode.getStyle();
        style.marginRight = '2px';
        style.marginLeft = '2px';
    },

    setPosition: function (val) {
        var template = 'ui-btn-{0}';
        this.__domNode.replaceClass(String.format(template, this.__position), String.format(template, val));
        this.__position = val;
    }
});